/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package angrypainters.components;

import angrypainters.application.GameScreenController;
import angrypainters.application.StartScreenController;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.concurrent.Task;
import javafx.geometry.Bounds;
import javafx.scene.paint.Color;

/**
 * manager of network connection
 *
 * @author Ahmed
 */
public class NetworkManager {

    DatagramSocket sendSocket;
    DatagramSocket recieveSocket;
    private int port;
    private String address;
    private StartScreenController startController;
    private GameScreenController gameController;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public StartScreenController getStartController() {
        return startController;
    }

    public void setStartController(StartScreenController startController) {
        this.startController = startController;
    }

    public GameScreenController getGameController() {
        return gameController;
    }

    public void setGameController(GameScreenController gameController) {
        this.gameController = gameController;
    }

    /**
     * sends the object message to the other player
     *
     * @param message message to send
     */
    public void sendData(final Object message) {
        try {
            sendSocket = new DatagramSocket();
            InetAddress receiverAddress = InetAddress.getByName(address);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream obj = new ObjectOutputStream(baos);
            obj.writeObject(message);
            byte[] buffer = baos.toByteArray();
            DatagramPacket packet = new DatagramPacket(
                    buffer, buffer.length, receiverAddress, getPort());
            sendSocket.send(packet);
            System.out.println("sendin"+message.getClass());
        } catch (UnknownHostException | SocketException ex) {
            Logger.getLogger(NetworkManager.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("host error");
        } catch (IOException ex) {
            Logger.getLogger(NetworkManager.class.getName()).log(Level.SEVERE, null, ex);
            System.out.println("io error");
        }
    }

    /**
     * Starts the listening port in a background task for any incoming messages
     */
    public void recieveData() {
        try {
            recieveSocket = new DatagramSocket(port);
        } catch (SocketException ex) {
            Logger.getLogger(NetworkManager.class.getName()).log(Level.SEVERE, null, ex);
        }
        Task task = new Task() {
            @Override
            protected Object call() throws Exception {
                while (true) {
                    try {
                        System.out.println("new line");
                        byte[] buffer = new byte[8192];
                        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                        while (true) {
                            recieveSocket.receive(packet);
                            
                            InputStream in = new ByteArrayInputStream(packet.getData(),packet.getOffset(),packet.getLength());
                            ObjectInputStream obj = new ObjectInputStream(in);
                            Message s = (Message) obj.readObject();
                            System.out.println("recieved"+s.type);
                            handleMessage(s);
                            Thread.sleep(50);
                        }
                    } catch (SocketException ex) {
                        Logger.getLogger(NetworkManager.class.getName()).log(Level.SEVERE, null, ex);
                        System.out.println("object class=so");
                    } catch (IOException ex) {
                        Logger.getLogger(NetworkManager.class.getName()).log(Level.SEVERE, null, ex);
                        System.out.println("object class=io");
                    } catch (ClassNotFoundException ex) {
                        Logger.getLogger(NetworkManager.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            }
        };
        Thread th = new Thread(task);
        th.setDaemon(true);
        th.start();
    }

    /**
     * handles the captured message
     *
     * @param s
     */
    private void handleMessage(Message s) {
        System.out.println("type"+s.type);
        switch (s.type) {
            case SwitchPlayer:
                gameController.getModel().setCurrentPlayer(gameController.getModel().getCurrentPlayer() == Player.guest ? Player.host : Player.guest);
                gameController.updatePlayer("CurrentPlayer: " + gameController.getModel().getCurrentPlayer());
                gameController.getModel().setOpponentScore(gameController.getModel().getOpponentScore() - 1);
                break;
            case Request:
                Settings set = (Settings) s.message;
                
                gameController.getModel().setPlayerType(Player.host);
                System.out.println("connected"+set.getColor());
                gameController.getModel().setOpponentColor(Color.valueOf(set.getColor()));
                gameController.getModel().setOpponentScore(set.getBallons());
                set.setColor(startController.getOption().getColor());
                sendData(new Message(MessageType.Ready, set));
                gameController.rewriteImages();
                startController.displayGame(null);
                
                
                break;
            case Ready:
                Settings set2 = (Settings) s.message;
                gameController.getModel().setPlayerType(Player.guest);
                gameController.getModel().setOpponentColor(Color.valueOf(set2.getColor()));
                gameController.getModel().setOpponentScore(set2.getBallons());
                gameController.rewriteImages();
                startController.displayGame(null);
                break;
            case HouseImage:
                System.out.println("setting image from network");
                gameController.setHostImage((ImageBounds) s.message);
                break;
            case Result:
                gameController.setResultTesxt((String) s.message);
                break;
        }
    }
}